﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace SimpleIR
{
	/// <summary>
	/// A representation for interning and tracking all the program variable names and fields.
	/// </summary>
	public sealed class IRIdentifierTable
	{
		//Internal table for variables
		private readonly Dictionary<string, IRVarName> m_varinterntable;
		private readonly Dictionary<Tuple<IRType, string>, IRStaticField> m_staticinterntable;

		public IRIdentifierTable()
		{
			this.m_varinterntable = new Dictionary<string, IRVarName>();
			this.m_staticinterntable = new Dictionary<Tuple<IRType, string>, IRStaticField>();
		}

		////////////////////////////////////////////
		//For local variables

		/// <summary>
		/// Intern a new local variable with the given name.
		/// </summary>
		internal IRVarName InternNewLocalVar(string name)
		{
			if(!this.m_varinterntable.ContainsKey(name))
				this.m_varinterntable.Add(name, new IRVarName(name));

			return this.m_varinterntable[name];
		}

		/// <summary>
		/// Lookup a given var name, which MUST already exist.
		/// </summary>
		public IRVarName LookupLocalVarName(string name)
		{ return this.m_varinterntable[name]; }

		/// <summary>
		/// Lookup a given var name, return the name of null if the name is not known.
		/// </summary>
		public IRVarName LookupLocalVarNameNullIfNotDefined(string name)
		{
			if(!this.m_varinterntable.ContainsKey(name))
				return null;

			return this.m_varinterntable[name];
		}

		////////////////////////////////////////////
		//For static fields

		/// <summary>
		/// Intern a new static field with the given info.
		/// </summary>
		internal IRStaticField InternNewStaticField(FieldQualifiers fq, IRType defClass, string name, IRType ftype)
		{
			Tuple<IRType, string> lookupPair = new Tuple<IRType, string>(defClass, name);
			if(!this.m_staticinterntable.ContainsKey(lookupPair))
				this.m_staticinterntable.Add(new Tuple<IRType, string>(defClass, name), new IRStaticField(fq, defClass, name, ftype));

			return this.m_staticinterntable[lookupPair];
		}

		/// <summary>
		/// Lookup a given static field, which MUST already exist.
		/// </summary>
		public IRStaticField LookupStaticField(IRType defClass, string name)
		{
			Tuple<IRType, string> lookupPair = new Tuple<IRType, string>(defClass, name);
			return this.m_staticinterntable[lookupPair];
		}

		/// <summary>
		/// Get all the static fields that appear in any type in this program.
		/// THIS IS SLOW AND COPIES -- DO NOT USE IN PERFORMANCE SENSITIVE LOCATIONS.
		/// </summary>
		public void FillVectorWithAllStaticFields(List<IRStaticField> sfv)
		{
			foreach(IRStaticField sf in this.m_staticinterntable.Values)
				sfv.Add(sf);
		}
	}
}
